#include "AdminChannelManager.h"
#include "AdminIChannel.h"
#include "AdminChannel.h"
#include "AdminConfiguration.h"

AgoraAdmin::IChannelManager*	AgoraAdmin::ChannelManager::_instance = NULL;

AgoraAdmin::ChannelManager::ChannelManager()
{
	this->LoadChannel();
}

AgoraAdmin::IChannelManager*	AgoraAdmin::ChannelManager::GetChannelManager(void)
{
	if (!ChannelManager::_instance)
		ChannelManager::_instance = new ChannelManager();
	return ChannelManager::_instance;
}

void				AgoraAdmin::ChannelManager::LoadChannel(void)
{
	//load from database //TODO a voir pour faire une suite de requete depuis le root ou recursif
	AgoraAdmin::IDatabase::DbResult* result = AgoraAdmin::Configuration::GetConfiguration()->GetDatabase()->SelectAllChannel();
	for (unsigned int idx = 0; idx < result->size(); idx++)
	{
		//AgoraAdmin::IChannel *parentChannel = NULL;
		//if ((*result->at(idx))["idParent"]->GetValueInt() != 0)
		
			//AgoraAdmin::IChannel *parentChannel = this->GetChannel((*result->at(idx))["idParent"]->GetValueInt());
			//this->_channel.push_back();
		//}
		AgoraAdmin::IChannel*	channel = new AgoraAdmin::Channel((*result->at(idx))["id"]->GetValueInt(), NULL, (*result->at(idx))["idParent"]->GetValueInt(), (*result->at(idx))["name"]->GetValueString(), (*result->at(idx))["maxNameLenght"]->GetValueInt(), (*result->at(idx))["password"]->GetValueString(), (*result->at(idx))["maxPasswordLenght"]->GetValueInt(), (*result->at(idx))["motd"]->GetValueString(), (*result->at(idx))["maxMotdLenght"]->GetValueInt(), (*result->at(idx))["description"]->GetValueString(), (*result->at(idx))["maxDescriptionLenght"]->GetValueInt(), (*result->at(idx))["visibility"]->GetValueBool(), (*result->at(idx))["maxUser"]->GetValueInt(), (*result->at(idx))["maxTalker"]->GetValueInt());
		this->_channel[channel->GetId()] = channel;
		/*if (parentChannel)
			parentChannel->AddChannelChild(channel);*/
	}
	std::map<unsigned int, IChannel*>::iterator	iteCurrent = this->_channel.begin();
	std::map<unsigned int, IChannel*>::iterator	iteEnd = this->_channel.end();
	while (iteCurrent != iteEnd)
	{
		if ((*iteCurrent).second->GetId() != 0 && (*iteCurrent).second->GetName() != "root")
		{
			this->_channel[(*iteCurrent).second->GetParentId()]->AddChannelChild((*iteCurrent).second);
			(*iteCurrent).second->SetParentNODB(this->_channel[(*iteCurrent).second->GetParentId()]);
		}
		++iteCurrent;
	}
	delete result;
}

AgoraAdmin::IChannel*	AgoraAdmin::ChannelManager::CreateChannel(const std::string& name, const unsigned int maxNameLenght, const std::string& password, const unsigned int maxPasswordLenght, const std::string& motd, const unsigned int maxMotdLenght, const std::string& description, const unsigned int maxDescriptionLenght, const bool visible, const unsigned int maxUser, const unsigned int maxTalker)
{
	//creer dans la base le channel 'Root'
	AgoraAdmin::Configuration::GetConfiguration()->GetDatabase()->CreateChannel(0, name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	AgoraAdmin::IChannel*	channel = new Channel(0, NULL, 0, name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	this->_channel[0] = channel;
	return channel;
}

AgoraAdmin::IChannel*	AgoraAdmin::ChannelManager::CreateChannel(IChannel* parent, const std::string& name, const unsigned int maxNameLenght, const std::string& password, const unsigned int maxPasswordLenght, const std::string& motd, const unsigned int maxMotdLenght, const std::string& description, const unsigned int maxDescriptionLenght, const bool visible, const unsigned int maxUser, const unsigned int maxTalker)
{
	//creer dans la base
	unsigned int id = AgoraAdmin::Configuration::GetConfiguration()->GetDatabase()->CreateChannel(parent->GetId(), name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	IChannel*	channel = new Channel(id, parent, parent->GetId(), name, maxNameLenght, password, maxPasswordLenght, motd, maxMotdLenght, description, maxDescriptionLenght, visible, maxUser, maxTalker);
	this->_channel[id] = channel;
	parent->AddChannelChild(channel);
	return channel;
}

void				AgoraAdmin::ChannelManager::DeleteChannel(std::stack<IUser*>& usrToMove)
{
	IChannel*	channelRoot = this->GetChannel(0);
	std::list<IChannel*>::iterator	iterCurrent = channelRoot->GetChannelChild().begin();
	std::list<IChannel*>::iterator	iterEnd = channelRoot->GetChannelChild().end();
	while (iterCurrent != iterEnd)
	{
		this->DeleteChannel((*iterCurrent), usrToMove);
		++iterCurrent;
	}
}

void				AgoraAdmin::ChannelManager::DeleteChannel(const unsigned int id, std::stack<IUser*>& usrToMove)
{
	IChannel*	channel = this->GetChannel(id);
	this->DeleteChannel(channel, usrToMove);
}

void				AgoraAdmin::ChannelManager::DeleteChildrens(IChannel* channel, std::stack<IUser*>& usrToMove)
{
	std::list<IUser*>	toMove;
	std::list<IUser*>::iterator	iteCurrent = channel->GetUser().begin();
	std::list<IUser*>::iterator	iteEnd = channel->GetUser().end();
	while (iteCurrent != iteEnd)
	{
		//(*iteCurrent)->SetCurrentChannel(NULL); prob UML include IUser dans IChannel et inversement :/ visiblement fixed
		//(*iteCurrent)->SetNoCurrentChannel(); //on reatribue plutot au channel root
		toMove.push_back(*iteCurrent);
		usrToMove.push(*iteCurrent);
		++iteCurrent;
	}
	iteCurrent = toMove.begin();
	iteEnd = toMove.end();
	while (iteCurrent != iteEnd)
	{
		this->MoveUser(channel->GetId(), 0, *iteCurrent);
		++iteCurrent;
	}
	std::list<IChannel*> toDel;

	//on applique le meme procede a tout les child du channel
	std::list<IChannel*>::iterator	iterCurrent = channel->GetChannelChild().begin();
	std::list<IChannel*>::iterator	iterEnd = channel->GetChannelChild().end();
	while (iterCurrent != iterEnd)
	{
		toDel.push_back((*iterCurrent));
		++iterCurrent;
	}
	iterCurrent = toDel.begin();
	iterEnd = toDel.end();
	while (iterCurrent != iterEnd)
	{
		this->DeleteChannel((*iterCurrent), usrToMove);
		++iterCurrent;
	}
}

void				AgoraAdmin::ChannelManager::DeleteChannel(IChannel* channel, std::stack<IUser*>& usrToMove)
{
	//suppression du channel lie aux users dans la liste des users du channel
	this->DeleteChildrens(channel, usrToMove);
	//suppression dans la base


	// a remettre apres debug
	channel->DeleteChannel();




	//et on enleve ce channel de la list des channel de son parent
	if (channel->HaveParent())
		channel->GetParent()->RemoveChannelChild(channel);

	this->_channel.erase(channel->GetId());//.remove(channel);
	delete channel;
}

void				AgoraAdmin::ChannelManager::MoveChannel(const unsigned int idChannel, const unsigned int idParent)
{
	this->GetChannel(idChannel)->SetParent(this->GetChannel(idParent));
}

AgoraAdmin::IChannel*	AgoraAdmin::ChannelManager::GetChannel(const unsigned int id)
{
	if (this->_channel.count(id))
		return this->_channel[id];
	return NULL;
/*
	std::map<unsigned int, IChannel*>::iterator	iteCurrent = this->_channel.begin();
	std::map<unsigned int, IChannel*>::iterator	iteEnd = this->_channel.end();
	while (iteCurrent != iteEnd)
	{
		if ((*iteCurrent).second->GetId() == id)
			return *iteCurrent;
		++iteCurrent;
	}*/
}

AgoraAdmin::IChannel*	AgoraAdmin::ChannelManager::GetChannel(const std::string& name)
{
	std::map<unsigned int, IChannel*>::iterator	iteCurrent = this->_channel.begin();
	std::map<unsigned int, IChannel*>::iterator	iteEnd = this->_channel.end();
	while (iteCurrent != iteEnd)
	{
		if ((*iteCurrent).second->GetName() == name)
			return (*iteCurrent).second;
		++iteCurrent;
	}
	return NULL;
}

std::map<unsigned int, AgoraAdmin::IChannel*>&	AgoraAdmin::ChannelManager::GetChannelList(void)
{
	return this->_channel;
}

bool	AgoraAdmin::ChannelManager::ChannelExists(const unsigned int idParent, const std::string& name)
{
	IDatabase::DbResult*	result = Configuration::GetConfiguration()->GetDatabase()->SelectChannel(idParent, name);

	if (result->size())
		return true;
	return false;
}

bool	AgoraAdmin::ChannelManager::MoveUser(const unsigned int idFromChannel, const unsigned int idToChannel, IUser* user)
{
	IChannel*	from = this->GetChannel(idFromChannel);
	IChannel*	to = this->GetChannel(idToChannel);
	if (!to || !from)
		return false;
	from->RemoveUser(user);
	to->AddUser(user);
	user->SetCurrentChannelId(to->GetId());
	return true;
}
